﻿using ELab.Client;
using ELab.Communication;
using ELab.Communication.Messages;
using ELab.Message;
using ELab.QuestionAnwer;
using ELab.Settings;
using System;
using System.Linq;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using ELab.Serialization.Data;
using ELab.Communication.Messages.ControllerMessages;
using ELab.Controls;
using ELab.Management;
using ELab.Teacher.Controls;
using ELab.Teacher.Apps;
using ELab.Hooking;
using WindowsInput;
using ELab.ImageProcess;
using ELab.SystemWatcher;
using System.IO;
using ELab.Core;
using System.Threading;
using System.Threading.Tasks;

namespace ELab.Teacher
{
    public partial class frmTeacherScreen : Form
    {
        #region Varial members
        Dictionary<string, Rectangle> _RemotingStudentScreenLst = new Dictionary<string, Rectangle>();
        private ELabClient _teacher;
        private User _CurrentUser = null, _ViewUser = null;
        private ClassMode CurrentClassMode = ClassMode.NONE, PreviousClassMode = ClassMode.NONE;
        private MessageKeyEventArgs enterKey = null;
        private GetUsersResponseMessage.UserResponse[] _users = null;
        private ElabWatcher watcher = new ElabWatcher();
        #endregion

        public frmTeacherScreen()
        {
            InitializeComponent();
        }

        #region support functions
        private void ShowTestResult(byte[] p)
        {
            TestExampleResult testResult = p.Deserialize<TestExampleResult>();
            ThreadHelperClass.ClearControl(this, flpTeacher, true);

            var studentLabel = new Label() { Width = flpTeacher.Width, Text = string.Format("Result for student: {0}", testResult.Student) };
            studentLabel.ForeColor = Color.DarkBlue;
            studentLabel.Font = new Font(base.Font, FontStyle.Bold);
            ThreadHelperClass.AddControl(this, flpTeacher, studentLabel);

            var studentLabel1 = new Label() { Width = flpTeacher.Width, Text = string.Format("Mark: {0}", testResult.Mark) };
            studentLabel1.ForeColor = Color.Red;
            studentLabel1.Font = new Font(base.Font, FontStyle.Bold);
            ThreadHelperClass.AddControl(this, flpTeacher, studentLabel1);

            int i = 1;
            foreach (QuestionResult result in testResult.Results)
            {
                Label lq = new Label();
                lq.Width = flpTeacher.Width;
                lq.Text = string.Format("Question {0}: {1}", i, result.Question.QuestionValue);
                ThreadHelperClass.AddControl(this, flpTeacher, lq);

                var istrue = result.Question.Answers.FirstOrDefault(c => c.IsRightAnwer).AnswerValue.Equals(result.Result);
                Label lq1 = new Label();
                lq1.Width = flpTeacher.Width;
                lq1.ForeColor = Color.Red;
                lq1.Text = "Result: " + istrue.ToString();
                ThreadHelperClass.AddControl(this, flpTeacher, lq1);
                i++;
            }
        }


        private void SendScreenToRemote(string strStudentAppName)
        {
            try
            {
                Image imgSend = null;
                ScreenCapture scrCapture = new ScreenCapture();

                imgSend = scrCapture.CaptureScreen();
                //using (var img = scrCapture.CaptureScreen())
                //{
                //    if (scvTeacher.Location == null || scvTeacher.Size == null) return;
                //    Point point = scvTeacher.Parent.PointToScreen(scvTeacher.Location);
                //    imgSend = CropImage(img, new Rectangle(point, scvTeacher.Size));
                //}
                EMessage message = new EMessage { Screen = new ScreenMessage { Screem = imgSend } };

                var ms = _teacher.CreateMessage();
                ms.DestinationApplicationName = strStudentAppName;
                ms.TransmitRule = MessageTransmitRules.NonPersistent;
                ms.MessageData = message.Data;

                ms.Send();
            }
            catch { }
        }

        public Image CropImage(Image source, Rectangle section)
        {
            // An empty bitmap which will hold the cropped image
            Bitmap bmp = new Bitmap(section.Width, section.Height);
            Graphics g = Graphics.FromImage(bmp);

            // Draw the given area (section) of the source image
            // at location 0,0 on the empty bitmap (bmp)
            g.DrawImage(source, 0, 0, section, GraphicsUnit.Pixel);

            return bmp;
        }

        private void SendMouseToRemote(string strStudentAppName, MessageMouseEventArgs mouse)
        {
            //EMessage message = new EMessage { Event = new EventMessage { MouseEvent = new MouseEventArgs( btn, Click, curPos.X, curPos.Y,0) } };

            EMessage message = new EMessage { Event = new EventMessage { MouseEvent = mouse } };

            var ms = _teacher.CreateMessage();
            ms.DestinationApplicationName = strStudentAppName;
            ms.TransmitRule = MessageTransmitRules.NonPersistent;
            ms.MessageData = message.Data;

            ms.Send();
        }

        private MessageMouseEventArgs GetMouseOverRemotingScreen(string strStudentAppName)
        {
            Point curPos = GetCursorPosition();
            Point screenPos = scvTeacher.PointToScreen(new Point(0, 0));
            MouseButtons btn = new System.Windows.Forms.MouseButtons();

            int Click = 0;
            int x = 0;
            int y = 0;
            MessageMouseEventArgs mouse = new MessageMouseEventArgs();
            //mouse.Location = new Point(curPos.X-screenPos.X, curPos.Y-screenPos.Y);
            mouse.X = curPos.X - screenPos.X;
            mouse.Y = curPos.Y - screenPos.Y;
            // Calulating the Shift cordinate

            Rectangle r = scvTeacher.ClientRectangle;
            if (_RemotingStudentScreenLst.ContainsKey(strStudentAppName))
            {
                r = _RemotingStudentScreenLst[strStudentAppName];
                double sCale1 = (double)scvTeacher.Width / r.Width;
                double sCale2 = (double)scvTeacher.Height / r.Height;
                double sCaleFactor = Math.Min(sCale1, sCale2);
                double RealWith = r.Width * sCaleFactor;
                double ReadHeight = r.Height * sCaleFactor;
                int ShiftX = (int)((scvTeacher.Width - RealWith)) / 2;
                int ShiftY = (int)((scvTeacher.Height - ReadHeight)) / 2;
                mouse.X -= ShiftX;
                mouse.Y -= ShiftY;
                mouse.ScreenWidth = (int)RealWith;
                mouse.ScreenHeight = (int)ReadHeight;
            }
            else
            {
                mouse.ScreenWidth = r.Width;
                mouse.ScreenHeight = r.Height;
            }
            return mouse;
        }

        private void SendKeyToRemote(string strStudentAppName, MessageKeyEventArgs enterKey)
        {
            EMessage message = new EMessage { Event = new EventMessage { KeyEvent = enterKey } };

            var ms = _teacher.CreateMessage();
            ms.DestinationApplicationName = strStudentAppName;
            ms.TransmitRule = MessageTransmitRules.NonPersistent;
            ms.MessageData = message.Data;

            ms.Send();
        }

        public static Point GetCursorPosition()
        {
            POINT lpPoint;
            GetCursorPos(out lpPoint);
            //bool success = User32.GetCursorPos(out lpPoint);
            // if (!success)

            return lpPoint;
        }

        /// <summary>
        /// Send file to remote users
        /// </summary>
        /// <param name="strStudentsAppName"></param>
        private void SendFilesToRemote(params string[] strStudentsAppName)
        {
            if (_CurrentUser == null) return;

            FilesSynchMessage msg = new FilesSynchMessage
            {
                Users = new List<string> { _CurrentUser.UserName },
                FileInfors = watcher.FileInfors
            };

            Parallel.ForEach(strStudentsAppName, strStudentAppName =>
            {
                EMessage message = new EMessage { Command = new CommandMessage { Body = msg.Data, CommandType = CommandType.RequestCheckFiles } };
                var ms = _teacher.CreateMessage();
                ms.DestinationApplicationName = strStudentAppName;
                ms.TransmitRule = MessageTransmitRules.NonPersistent;
                ms.MessageData = message.Data;
                ms.Send();
            });
        }

        private void ProcessCheckFile(EMessage retrieveMess)
        {
            FilesSynchMessage synMsg = FilesSynchMessage.FromData(retrieveMess.Command.Body);
            if (synMsg == null || synMsg.Users == null || synMsg.Users.Count == 0) return;

            //File need to send
            var sendInfos = synMsg.FileInfors;
            if (sendInfos != null && sendInfos.Count > 0)
            {
                Parallel.ForEach(sendInfos, sendInfo =>
                {
                    var FullPath = Path.Combine(SystemConfiguration.CurrentPath, SystemConfiguration.TransferFolder, sendInfo.FileName);
                    FileMessage fileMsg = new FileMessage { FilePath = FullPath, FileData = File.ReadAllBytes(FullPath) };
                    EMessage message = new EMessage { Command = new CommandMessage { Body = fileMsg.Data, CommandType = CommandType.RequestSendFiles } };
                    var ms = _teacher.CreateMessage();
                    ms.TransmitRule = MessageTransmitRules.NonPersistent;
                    ms.MessageData = message.Data;
                    Parallel.ForEach(synMsg.Users, user =>
                    {
                        ms.DestinationApplicationName = user;
                        ms.Send();
                    });
                });
            }
        }

        private void ProcessReceiverFile(EMessage retrieveMess)
        {
            FileMessage synMsg = new FileMessage(retrieveMess.Command.Body);
            if (synMsg == null) return;
            var index = synMsg.FilePath.LastIndexOf('\\');
            var filename = (index > 0 ? synMsg.FilePath.Substring(index + 1) : synMsg.FilePath);
            var FullPath = Path.Combine(SystemConfiguration.CurrentPath, SystemConfiguration.TransferFolder, filename);
            File.WriteAllBytes(FullPath, synMsg.FileData);
        }
        #endregion

        #region Button  & Form Events
        private void btnUserManager_Click(object sender, EventArgs e)
        {
            var serverInfor = ELabSettings.Instance.Servers.FirstOrDefault();
            string ipAddressServer = serverInfor == null ? CommunicationConsts.DefaultIpAddress : serverInfor.IpAddress;
            int portServer = serverInfor == null ? CommunicationConsts.DefaultPort : serverInfor.Port;
            var controller = new ELab.Management.ELabController(ipAddressServer, portServer);
            var usersForm = new UsersForm(controller);
            usersForm.ShowDialog();
        }

        private void btnRefresh_Click(object sender, EventArgs e)
        {
            RefreshUser();

            if (_users != null)
            {
                lctStudents.Users = _users;
            }
        }

        private void RefreshUser()
        {
            ELabController controller = null;
            try
            {
                int attent = 0, maxattent = SystemConfiguration.ReconnectTimes;
                var serverInfor = ELabSettings.Instance.Servers.FirstOrDefault();
                string ipAddressServer = serverInfor == null ? CommunicationConsts.DefaultIpAddress : serverInfor.IpAddress;
                int portServer = serverInfor == null ? CommunicationConsts.DefaultPort : serverInfor.Port;

                while (attent < maxattent)
                {
                    try
                    {
                        controller = new ELabController(ipAddressServer, portServer);
                        controller.Connect();
                        var message = controller.SendMessageAndGetResponse(new GetUsersMessage());
                        var userListMessage = message as GetUsersResponseMessage;
                        controller.Disconnect();

                        if (userListMessage != null && userListMessage.Users != null)
                        {
                            _users = userListMessage.Users.Where(x => x.Type == UserType.Student).ToArray();
                        }
                        break;
                    }
                    catch (Exception es)
                    {
                        attent++;
                        if (attent >= maxattent) throw es;
                    }
                    finally
                    {
                        if (controller != null) controller.Disconnect();
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
                this.Close();
            }
            finally
            {
                if (controller != null) controller.Disconnect();
            }
        }

        private void btnCreateTest_Click(object sender, EventArgs e)
        {
            scvTeacher.Visible = false;
            flpTeacher.Visible = true;
            ctrlQAManagement frmQ = new ctrlQAManagement();
            frmQ.Cancel += frmQ_Cancel;
            frmQ.TeacherControl = _teacher;
            frmQ.Users = lctStudents.Users;
            flpTeacher.Controls.Clear();
            flpTeacher.Controls.Add(frmQ);
        }

        void frmQ_Cancel(object sender, EventArgs e)
        {
            scvTeacher.Visible = true;
            flpTeacher.Visible = false;
        }

        private void frmTeacherScreen_FormClosing(object sender, FormClosingEventArgs e)
        {
            try
            {
                if (_ViewUser != null && CurrentClassMode != ClassMode.NONE)
                {
                    var ms = _teacher.CreateMessage();
                    ms.DestinationApplicationName = _ViewUser.UserName;
                    ms.TransmitRule = MessageTransmitRules.NonPersistent;
                    CommandMessage comm = new CommandMessage();
                    if (CurrentClassMode == ClassMode.REMOTE)
                        comm.CommandType = CommandType.RequestFinishRemote;
                    if (CurrentClassMode == ClassMode.VIEW_ONLY)
                        comm.CommandType = CommandType.RequestFinishCapture;
                    if (CurrentClassMode == ClassMode.LOCKED)
                        comm.CommandType = CommandType.RequestUnlockInput;
                    EMessage message = new EMessage { Command = comm };
                    ms.MessageData = message.Data;
                    ms.Send();
                    CurrentClassMode = ClassMode.NONE;
                }

                if (_teacher != null)
                {
                    _teacher.Disconnect();
                    _teacher.Dispose();
                }
            }
            catch
            {
            }
        }

        private void frmTeacherScreen_KeyDown(object sender, KeyEventArgs e)
        {
            enterKey = new MessageKeyEventArgs(e.KeyData);
            enterKey.Alt = e.Alt;
            enterKey.Control = e.Control;
            enterKey.KeyCode = e.KeyCode;
            enterKey.KeyData = e.KeyData;
            enterKey.KeyValue = e.KeyValue;
            enterKey.Modifiers = e.Modifiers;
            enterKey.Shift = e.Shift;
            enterKey.UpDownStatus = 1;// down
            enterKey.SuppressKeyPress = e.SuppressKeyPress;


            if (_ViewUser != null)
                SendKeyToRemote(_ViewUser.UserName, enterKey);

            e.Handled = true;


        }

        private void frmTeacherScreen_KeyUp(object sender, KeyEventArgs e)
        {
            enterKey = new MessageKeyEventArgs(e.KeyData);
            enterKey.Alt = e.Alt;
            enterKey.Control = e.Control;
            enterKey.KeyCode = e.KeyCode;
            enterKey.KeyData = e.KeyData;
            enterKey.KeyValue = e.KeyValue;
            enterKey.Modifiers = e.Modifiers;
            enterKey.Shift = e.Shift;
            enterKey.UpDownStatus = 0;// down
            enterKey.SuppressKeyPress = e.SuppressKeyPress;


            if (_ViewUser != null)
                SendKeyToRemote(_ViewUser.UserName, enterKey);

            e.Handled = true;
        }

        private void frmTeacherScreen_Load(object sender, EventArgs e)
        {

            ELabController controller = null;
            try
            {
                int attent = 0, maxattent = SystemConfiguration.ReconnectTimes;
                var serverInfor = ELabSettings.Instance.Servers.FirstOrDefault();
                string ipAddressServer = serverInfor == null ? CommunicationConsts.DefaultIpAddress : serverInfor.IpAddress;
                int portServer = serverInfor == null ? CommunicationConsts.DefaultPort : serverInfor.Port;

                while (attent < maxattent)
                {
                    try
                    {
                        controller = new ELabController(ipAddressServer, portServer);
                        controller.ReConnectServerOnError = true;
                        controller.Connect();
                        var message = controller.SendMessageAndGetResponse(new GetUsersMessage());
                        var userListMessage = message as GetUsersResponseMessage;
                        controller.Disconnect();

                        if ((userListMessage != null && userListMessage.Users != null) && (userListMessage.Users.Length > 0))
                        {
                            frmLogin login = new frmLogin();
                            login.ShowDialog();
                            _CurrentUser = login.uLoginControl.CurrentUser;
                            ctrTeacher.CurrentUser = _CurrentUser;

                            if (_CurrentUser == null) Application.Exit();

                            _teacher = new ELabClient(_CurrentUser.UserName, ipAddressServer, portServer);
                            _teacher.MessageReceived += _eLabClient_MessageReceived;
                            this.FormClosing += frmTeacherScreen_FormClosing;
                            _teacher.ReConnectServerOnError = true;
                            _teacher.Connect();

                            //update status 
                            controller.Connect();
                            userListMessage = (GetUsersResponseMessage)controller.SendMessageAndGetResponse(new GetUsersMessage());
                            controller.Disconnect();
                            var users = userListMessage.Users.Where(x => x.Type != UserType.Teacher).ToArray();
                            lctStudents.Users = users;
                            break;
                        }
                        else
                        {
                            var usersForm = new UsersForm(controller);
                            usersForm.ShowDialog();
                            break;
                        }
                    }
                    catch (Exception es)
                    {
                        attent++;
                        if (attent >= maxattent) throw es;
                    }
                    finally
                    {
                        if (controller != null) controller.Disconnect();
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
                this.Close();
            }
            finally
            {
                if (controller != null) controller.Disconnect();
            }
        }

        private void btnChangePass_Click(object sender, EventArgs e)
        {
            var serverInfor = ELabSettings.Instance.Servers.FirstOrDefault();
            string ipAddressServer = serverInfor == null ? CommunicationConsts.DefaultIpAddress : serverInfor.IpAddress;
            int portServer = serverInfor == null ? CommunicationConsts.DefaultPort : serverInfor.Port;
            var controller = new ELabController(ipAddressServer, portServer);

            ChangePassForm frm = new ChangePassForm();
            frm.Controller = controller;
            frm.CurrentUser = _CurrentUser;
            frm.ShowDialog();
            btnRefresh_Click(null, null);
        }

        private void flpTeacher_MouseLeave(object sender, EventArgs e)
        {
            if (CurrentClassMode == ClassMode.REMOTE && _ViewUser != null)
            {
                MessageMouseEventArgs mouse = GetMouseOverRemotingScreen(_ViewUser.UserName);
                mouse.Button = MouseButtons.Left;
                mouse.Clicks = 1;
                mouse.ButtonStatus = 0;// up
                SendMouseToRemote(_ViewUser.UserName, mouse);

                mouse.Button = MouseButtons.Right;
                mouse.Clicks = 1;
                mouse.ButtonStatus = 0;// up

                SendMouseToRemote(_ViewUser.UserName, mouse);
            }

        }
        private DateTime beginTime = DateTime.Now;
        private bool isFirst = true;
        private void tmInput_Tick(object sender, EventArgs e)
        {
            //Synch files
            if (this._users != null && _users.Any(x => x.IsOnline))
            {
                var endTime = DateTime.Now;
                TimeSpan timesp = endTime - beginTime;
                if (isFirst || timesp.TotalSeconds > 5 * SystemConfiguration.ConnectTimeOut)
                {
                    SendFilesToRemote(_users.Where(x => x.IsOnline).Select(x => x.UserName).ToArray());
                    beginTime = endTime;
                    isFirst = false;
                }
            }

            if (CurrentClassMode != ClassMode.STUDENT_REMOTE) return;
            SendScreenToRemote(_ViewUser.ApplicationName);
            string strKey = "";
            string strMouse = "";
            if ((_Keys.Count > 0) || (_Mouses.Count > 0))
            {
                lblTeacherName.Text = "";
                if (_Keys.Count > 0) SendKey(ref _Keys);
                if (_Mouses.Count > 0) SendMouse(ref _Mouses);

                for (int i = 0; i < _Keys.Count; i++)
                {
                    strKey += "(" + _Keys[i].KeyCode + ",alt:" + _Keys[i].Alt.ToString()
                        + ",^:" + _Keys[i].Control.ToString() + "Shift:" + _Keys[i].Shift.ToString() + ");";
                }
                lblTeacherName.Text += strKey;
                for (int i = 0; i < _Mouses.Count; i++)
                {
                    strMouse += "(" + _Mouses[i].Location.X.ToString() + "," + _Mouses[i].Location.Y.ToString() + ";" + _Mouses[i].Button.ToString() + ");";

                }
                lblTeacherName.Text += strMouse;

                _Keys.Clear();
                _Mouses.Clear();
            }
        }
        #endregion

        #region Screen to view events

        void SendKey(ref List<MessageKeyEventArgs> _Keys)
        {
            for (int i = 0; i < _Keys.Count; i++)
            {

                if (_Keys[i].UpDownStatus == 1)// KeyDown
                {
                    if (_Keys[i].Control)
                        InputSimulator.SimulateKeyDown(VirtualKeyCode.CONTROL);
                    if (_Keys[i].Shift)
                        InputSimulator.SimulateKeyDown(VirtualKeyCode.SHIFT);
                    if (_Keys[i].KeyCode > 0)
                        InputSimulator.SimulateKeyDown((VirtualKeyCode)((ushort)_Keys[i].KeyValue));
                }
                else
                    if (_Keys[i].UpDownStatus == 0)// KeyUp
                    {
                        if (_Keys[i].Control)
                            InputSimulator.SimulateKeyUp(VirtualKeyCode.CONTROL);
                        if (_Keys[i].Shift)
                            InputSimulator.SimulateKeyUp(VirtualKeyCode.SHIFT);
                        if (_Keys[i].KeyCode > 0)
                            InputSimulator.SimulateKeyUp((VirtualKeyCode)((ushort)_Keys[i].KeyValue));
                    }
            }

            _Keys.Clear();

        }
        void SendMouse(ref List<MessageMouseEventArgs> _Mouses)
        {
            //get screen size
            if (_Mouses == null) return;
            Rectangle resolution = Screen.PrimaryScreen.Bounds;
            for (int i = 0; i < _Mouses.Count; i++)
            {
                double scale1 = (double)resolution.Width / (double)_Mouses[i].ScreenWidth;
                double scale2 = (double)resolution.Height / (double)_Mouses[i].ScreenHeight;
                double scaleFactor = Math.Max(scale1, scale2);
                double xShift = (resolution.Width - _Mouses[i].ScreenWidth * scaleFactor) / 2;
                double yShift = (resolution.Height - _Mouses[i].ScreenHeight * scaleFactor) / 2;

                MouseSimulator.MouseMove((int)(xShift + _Mouses[i].X * scaleFactor),
                   (int)(yShift + _Mouses[i].Y * scaleFactor));
                if (_Mouses[i].ButtonStatus == 1)// mouse down
                {

                    if (_Mouses[i].Clicks == 1)
                    {
                        if (_Mouses[i].Button == MouseButtons.Left)
                            MouseSimulator.LeftMouseDown();
                        //MouseSimulator.ClickLeftMouseButton();
                        else
                            if (_Mouses[i].Button == MouseButtons.Right)
                                MouseSimulator.RightMouseDown();
                        //MouseSimulator.ClickRightMouseButton();
                    }
                    else
                        if (_Mouses[i].Clicks == 2)// Double click
                        {

                            MouseSimulator.ClickLeftMouseButton();
                            MouseSimulator.ClickLeftMouseButton();
                        }
                }
                else
                    if (_Mouses[i].ButtonStatus == 0)// Mouse up
                    {
                        if (_Mouses[i].Clicks == 1)
                        {
                            if (_Mouses[i].Button != MouseButtons.None)
                            {


                                if (_Mouses[i].Button == MouseButtons.Left)
                                    MouseSimulator.LeftMouseUp();
                                else
                                    if (_Mouses[i].Button == MouseButtons.Right)
                                        MouseSimulator.RightMouseUp();
                            }

                        }
                    }

                if (_Mouses[i].Delta != 0)
                {
                    MouseSimulator.MouseWheel((uint)_Mouses[i].Delta);

                }
            }
            _Mouses.Clear();

        }
        void SendMouse2(ref List<MessageMouseEventArgs> _Mouses)
        {
            //get screen size
            if (_Mouses == null) return;
            for (int i = 0; i < _Mouses.Count; i++)
            {
                double scale1 = (double)scvTeacher.Width / (double)_Mouses[i].ScreenWidth;
                double scale2 = (double)scvTeacher.Height / (double)_Mouses[i].ScreenHeight;
                double scaleFactor = Math.Min(scale1, scale2);



                Point screenPos = scvTeacher.PointToScreen(new Point(scvTeacher.Width / 2, scvTeacher.Height / 2));

                MouseSimulator.MouseMove((int)(_Mouses[i].X * scaleFactor) + screenPos.X, (int)(_Mouses[i].Y * scaleFactor) + screenPos.Y);
                if (_Mouses[i].ButtonStatus == 1)// mouse down
                {

                    if (_Mouses[i].Clicks == 1)
                    {
                        if (_Mouses[i].Button == MouseButtons.Left)
                            MouseSimulator.LeftMouseDown();
                        //MouseSimulator.ClickLeftMouseButton();
                        else
                            if (_Mouses[i].Button == MouseButtons.Right)
                                MouseSimulator.RightMouseDown();
                        //MouseSimulator.ClickRightMouseButton();
                    }
                    else
                        if (_Mouses[i].Clicks == 2)// Double click
                        {

                            MouseSimulator.ClickLeftMouseButton();
                            MouseSimulator.ClickLeftMouseButton();
                        }
                }
                else
                    if (_Mouses[i].ButtonStatus == 0)// Mouse up
                    {
                        if (_Mouses[i].Clicks == 1)
                        {
                            if (_Mouses[i].Button != MouseButtons.None)
                            {


                                if (_Mouses[i].Button == MouseButtons.Left)
                                    MouseSimulator.LeftMouseUp();
                                else
                                    if (_Mouses[i].Button == MouseButtons.Right)
                                        MouseSimulator.RightMouseUp();
                            }

                        }
                    }

                if (_Mouses[i].Delta != 0)
                {
                    MouseSimulator.MouseWheel((uint)_Mouses[i].Delta);

                }
            }
            _Mouses.Clear();

        }
        private void scvTeacher_Click(object sender, EventArgs e)
        {


        }

        private void scvTeacher_MouseHover(object sender, EventArgs e)
        {

        }

        private void scvTeacher_MouseClick(object sender, MouseEventArgs e)
        {


        }

        private void scvTeacher_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            //if (CurrentClassMode == ClassMode.REMOTE && _ViewUser != null)
            //{
            //    MessageMouseEventArgs mouse = GetMouseOverRemotingScreen(_ViewUser.UserName);
            //    mouse.Button = e.Button;
            //    mouse.Clicks = 2;
            //    SendMouseToRemote(_ViewUser.UserName, mouse);
            //}
        }
        private void scvTeacher_MouseWheel(object sender, MouseEventArgs e)
        {
            if (CurrentClassMode == ClassMode.REMOTE && _ViewUser != null)
            {
                MessageMouseEventArgs mouse = GetMouseOverRemotingScreen(_ViewUser.UserName);
                mouse.Delta = e.Delta;
                mouse.Button = MouseButtons.None;
                SendMouseToRemote(_ViewUser.UserName, mouse);

            }
        }
        private void scvTeacher_MouseDown(object sender, MouseEventArgs e)
        {
            //lblTeacherName.Text += "D";
            if (CurrentClassMode == ClassMode.REMOTE && _ViewUser != null)
            {
                MessageMouseEventArgs mouse = GetMouseOverRemotingScreen(_ViewUser.UserName);
                mouse.Button = e.Button;
                mouse.Clicks = e.Clicks;
                mouse.ButtonStatus = 1;// down
                SendMouseToRemote(_ViewUser.UserName, mouse);

                _CurMouseStatus = 1;// Mouse down
                _CurMouseButton = e.Button;
            }
        }
        private void scvTeacher_MouseUp(object sender, MouseEventArgs e)
        {
            //lblTeacherName.Text += "U";
            if (CurrentClassMode == ClassMode.REMOTE && _ViewUser != null)
            {
                MessageMouseEventArgs mouse = GetMouseOverRemotingScreen(_ViewUser.UserName);
                mouse.Button = e.Button;
                mouse.Clicks = 1;// e.Clicks;
                mouse.ButtonStatus = 0;// up
                SendMouseToRemote(_ViewUser.UserName, mouse);

                _CurMouseButton = MouseButtons.None;
                _CurMouseStatus = 0;// Mouse up
                _CurMouseButton = e.Button;
            }
        }

        private void scvTeacher_DoubleClick(object sender, EventArgs e)
        {

        }


        byte _CurMouseStatus = 0;// mouse up
        MouseButtons _CurMouseButton = MouseButtons.None;
        private void scvTeacher_MouseMove(object sender, MouseEventArgs e)
        {
            //if ((!string.IsNullOrEmpty(lblTeacherName.Text)) && (lblTeacherName.Text[lblTeacherName.Text.Length-1]!='.'))
            //    lblTeacherName.Text += ".";
            if (CurrentClassMode == ClassMode.REMOTE && _ViewUser != null)
            {
                MessageMouseEventArgs mouse = GetMouseOverRemotingScreen(_ViewUser.UserName);
                //if (_CurMouseButton == MouseButtons.None)
                mouse.Clicks = 0;
                //else
                //    mouse.Clicks = 1;// drag
                mouse.Button = MouseButtons.None;
                //mouse.ButtonStatus = _CurMouseStatus;
                SendMouseToRemote(_ViewUser.UserName, mouse);

            }
        }
        #endregion

        #region List students events
        private void lctStudents_ViewOnlyItemRequested(object sender, EventArgs e)
        {
            scvTeacher.Visible = true;
            flpTeacher.Visible = false;
            var viewUser = (InforControl)sender;
            if (_teacher != null)
            {
                var ms = _teacher.CreateMessage();
                ms.DestinationApplicationName = viewUser.CurrentUser.UserName;
                ms.TransmitRule = MessageTransmitRules.NonPersistent;
                CommandMessage comm = new CommandMessage { CommandType = CommandType.RequestCaptureScr };
                EMessage message = new EMessage { Command = comm };
                ms.MessageData = message.Data;
                ms.Send();
            }
            _ViewUser = viewUser.CurrentUser;
            PreviousClassMode = CurrentClassMode;
            CurrentClassMode = ClassMode.VIEW_ONLY;
        }

        private void lctStudents_RemoteItemRequested(object sender, EventArgs e)
        {
            scvTeacher.Visible = true;
            flpTeacher.Visible = false;
            var viewUser = (InforControl)sender;
            if (_teacher != null)
            {
                var ms = _teacher.CreateMessage();
                ms.DestinationApplicationName = viewUser.CurrentUser.UserName;
                ms.TransmitRule = MessageTransmitRules.NonPersistent;
                CommandMessage comm = new CommandMessage { CommandType = CommandType.RequestRemote };
                EMessage message = new EMessage { Command = comm };
                ms.MessageData = message.Data;
                ms.Send();
            }
            _ViewUser = viewUser.CurrentUser;
            PreviousClassMode = CurrentClassMode;
            CurrentClassMode = ClassMode.REMOTE;
        }

        private void lctStudents_StopViewItemRequested(object sender, EventArgs e)
        {
            scvTeacher.Visible = true;
            flpTeacher.Visible = false;
            var viewUser = (InforControl)sender;
            if (_teacher != null)
            {
                var ms = _teacher.CreateMessage();
                ms.DestinationApplicationName = viewUser.CurrentUser.UserName;
                ms.TransmitRule = MessageTransmitRules.NonPersistent;
                CommandMessage comm = new CommandMessage { CommandType = CommandType.RequestFinishCapture };
                EMessage message = new EMessage { Command = comm };
                ms.MessageData = message.Data;
                ms.Send();
            }
            _ViewUser = null;
            CurrentClassMode = PreviousClassMode;
        }

        private void lctStudents_LockItemRequested(object sender, EventArgs e)
        {
            scvTeacher.Visible = true;
            flpTeacher.Visible = false;
            var viewUser = (InforControl)sender;
            if (_teacher != null)
            {
                var ms = _teacher.CreateMessage();
                ms.DestinationApplicationName = viewUser.CurrentUser.UserName;
                ms.TransmitRule = MessageTransmitRules.NonPersistent;
                CommandMessage comm = new CommandMessage { CommandType = CommandType.RequestLockInput };
                EMessage message = new EMessage { Command = comm };
                ms.MessageData = message.Data;
                ms.Send();
            }
            PreviousClassMode = CurrentClassMode;
            CurrentClassMode = ClassMode.LOCKED;
        }

        private void lctStudents_UnlockItemRequested(object sender, EventArgs e)
        {
            scvTeacher.Visible = true;
            flpTeacher.Visible = false;
            var viewUser = (InforControl)sender;
            if (_teacher != null)
            {
                var ms = _teacher.CreateMessage();
                ms.DestinationApplicationName = viewUser.CurrentUser.UserName;
                ms.TransmitRule = MessageTransmitRules.NonPersistent;
                CommandMessage comm = new CommandMessage { CommandType = CommandType.RequestUnlockInput };
                EMessage message = new EMessage { Command = comm };
                ms.MessageData = message.Data;
                ms.Send();
            }
            CurrentClassMode = PreviousClassMode;
        }

        private void lctStudents_ControMeItemRequested(object sender, EventArgs e)
        {
            var viewUser = (InforControl)sender;
            if (CurrentClassMode == ClassMode.STUDENT_REMOTE)
            {
                //stop
                CurrentClassMode = PreviousClassMode;
                if (_teacher != null)
                {
                    var ms = _teacher.CreateMessage();
                    ms.DestinationApplicationName = viewUser.CurrentUser.UserName;
                    ms.TransmitRule = MessageTransmitRules.NonPersistent;
                    CommandMessage comm = new CommandMessage { CommandType = CommandType.RequestStopStudentControl };
                    EMessage message = new EMessage { Command = comm };
                    ms.MessageData = message.Data;
                    ms.Send();
                }
                _ViewUser = viewUser.CurrentUser;
            }
            else
            {
                scvTeacher.Visible = true;
                flpTeacher.Visible = false;

                if (_teacher != null)
                {
                    var ms = _teacher.CreateMessage();
                    ms.DestinationApplicationName = viewUser.CurrentUser.UserName;
                    ms.TransmitRule = MessageTransmitRules.NonPersistent;
                    CommandMessage comm = new CommandMessage { CommandType = CommandType.RequestStudentControl };
                    EMessage message = new EMessage { Command = comm };
                    ms.MessageData = message.Data;
                    ms.Send();
                }
                _ViewUser = viewUser.CurrentUser;
                PreviousClassMode = CurrentClassMode;
                CurrentClassMode = ClassMode.STUDENT_REMOTE;
            }
        }
        #endregion

        #region Overide & dllimport functions
        protected override bool ProcessCmdKey(ref System.Windows.Forms.Message msg, Keys keyData)
        {
            if ((int)keyData == 13 && CurrentClassMode == ClassMode.REMOTE)
            {
                enterKey = new MessageKeyEventArgs(Keys.Return);
                enterKey.Alt = false;
                enterKey.Control = false;
                enterKey.KeyCode = Keys.Enter;
                enterKey.KeyData = Keys.Enter;
                enterKey.KeyValue = 13;
                enterKey.Modifiers = Keys.Enter;
                enterKey.Shift = false;
                enterKey.UpDownStatus = 1;// down
                if (_ViewUser != null)
                {
                    SendKeyToRemote(_ViewUser.UserName, enterKey);
                    enterKey.UpDownStatus = 0;// down
                    SendKeyToRemote(_ViewUser.UserName, enterKey);
                }
            }

            // Call the base class
            //return true;
            return base.ProcessCmdKey(ref msg, keyData);
        }
        //-------------------------
        [StructLayout(LayoutKind.Sequential)]
        public struct POINT
        {
            public int X;
            public int Y;

            public static implicit operator Point(POINT point)
            {
                return new Point(point.X, point.Y);
            }
        }
        [DllImport("user32.dll")]
        public static extern bool GetCursorPos(out POINT lpPoint);

        protected override void OnKeyPress(KeyPressEventArgs e)
        {
            //if (_ViewUser != null)
            //{
            //    enterKey.KeyCode = (Keys)e.KeyChar;

            //    SendKeyToRemote(_ViewUser.UserName, enterKey);

            //    e.Handled = true;
            //    //----------------------------
            //    //base.OnKeyPress(e);
            //}
        }
        #endregion

        #region Message events
        List<MessageKeyEventArgs> _Keys = new List<MessageKeyEventArgs>();
        List<MessageMouseEventArgs> _Mouses = new List<MessageMouseEventArgs>();
        private void _eLabClient_MessageReceived(object sender, MessageReceivedEventArgs e)
        {
            e.Message.Acknowledge();
            EMessage mess = new EMessage(e.Message.MessageData);

            if (!mess.IsValidate) return;


            if ((mess.Event != null) && (mess.Event.KeyEvent != null))
            {

                _Keys.Add(mess.Event.KeyEvent);
            }
            else
            {
                if ((mess.Event != null) && (mess.Event.MouseEvent != null))
                {
                    _Mouses.Add(mess.Event.MouseEvent);
                }
                else
                {
                    if (mess.Command != null)
                    {
                        switch (mess.Command.CommandType)
                        {
                            case CommandType.None:
                                break;
                            case CommandType.RequestCaptureScr:
                                break;
                            case CommandType.RequestLockInput:
                                break;
                            case CommandType.ResponseLockInput:
                                break;
                            case CommandType.RequestUnlockInput:
                                break;
                            case CommandType.ResponseUnlockInput:
                                break;
                            case CommandType.RequestFinishCapture:
                                break;
                            case CommandType.ResponseFinishCapture:
                                break;
                            case CommandType.RequestTestExample:
                                break;
                            case CommandType.RequestTestExample_HandUp:
                                break;
                            case CommandType.RequestTestResult:
                                if (mess.Command != null)
                                {
                                    MessageBox.Show("Student finished test");
                                    ShowTestResult(mess.Command.Body);
                                }
                                break;
                            case CommandType.RequestTableExampleResult:
                                if (mess.Command != null)
                                {
                                    MessageBox.Show("Student finished test");
                                    ShowTableTestResult(mess.Command.Body);
                                }
                                break;

                            case CommandType.ResponseCheckFiles:
                                ProcessCheckFile(mess);
                                break;

                            case CommandType.RequestSendFiles:
                                ProcessReceiverFile(mess);
                                break;
                            default:
                                break;
                        }
                    }
                }
            }

            if (mess.Screen != null)
            {
                var img = mess.Screen.Screem;
                scvTeacher.Image = img;

                if (_ViewUser != null && !_RemotingStudentScreenLst.ContainsKey(_ViewUser.UserName))
                {
                    _RemotingStudentScreenLst.Add(_ViewUser.UserName, new Rectangle(0, 0, scvTeacher.Image.Width, scvTeacher.Image.Height));
                }
            }
        }

        private void ShowTableTestResult(byte[] p)
        {
            TestExampleResult testResult = p.Deserialize<TestExampleResult>();
            ThreadHelperClass.ClearControl(this, flpTeacher, true);

            var studentLabel = new Label() { Width = flpTeacher.Width, Text = string.Format("Result for student: {0}", testResult.Student) };
            studentLabel.ForeColor = Color.DarkBlue;
            studentLabel.Font = new Font(base.Font, FontStyle.Bold);
            ThreadHelperClass.AddControl(this, flpTeacher, studentLabel);

            ctrlTableAnswer answer = new ctrlTableAnswer();
            answer.testResult = testResult;
            answer.ShowResult();
            ThreadHelperClass.AddControl(this, flpTeacher, answer);
        }

        #endregion
    }
}
